<template>
  <m-window-frame
    :title="title"
    style="height: 100vh"
    :cancelText="''"
    :okText="'关 闭'"
    class="v-create-exchange-editor-manager"
    @cancel="handleCancel"
    @ok="handleCancel"
  >
    <div class="_main g-fd-c">
      <AttrTips
        class="_main-title g-flex-0"
        :type="exchangeType + 'Manager'"
      ></AttrTips>
      <div class="_main-content">
        <div class="button-area">
          <div
            class="button-item"
            @click="createExchange"
          >
            <img
              src="statics/icons/app/add.svg"
              alt=""
            />
            <span>{{ $t("新增") }}</span>
          </div>
          <div
            class="button-item"
            :class="{ disabled: selectedRowIds.size === 0 }"
            @click="deleteExchange"
          >
            <img
              src="statics/icons/table/icondelete2.svg"
              alt=""
            />
            <span>{{ $t("删除") }}</span>
          </div>
          <!-- <div class="button-item">
            <img src="statics/icons/app/showInherited.svg" alt="">
            <span>{{ $t('显示继承') }}</span>
          </div>
          <div class="button-item">
            <img src="statics/icons/app/showAggregated.svg" alt="">
            <span>{{ $t('显示聚合') }}</span>
          </div> -->
        </div>
        <div class="table-area">
          <ag-grid-vue
            style="height: 100%"
            class="ag-theme-alpine ag-theme-mdesigntheme"
            :getRowId="getRowId"
            :columnDefs="columnDefs"
            :rowData="rowData"
            :defaultColDef="defaultColDef"
            :getRowHeight="getRowHeight"
            :headerHeight="26"
            :rowBuffer="5"
            :suppressNoRowsOverlay="true"
            :context="{ relationId }"
            rowSelection="single"
            @grid-ready="onGridReady"
            @viewport-changed="onViewportChanged"
            @cell-clicked="onCellClicked"
            @selection-changed="onSelectionChanged"
            @cell-context-menu="onCellContextMenu"
          ></ag-grid-vue>
        </div>
        <!-- <div class="bar-area">
          <div class="bar-item">
            <div class="bar"></div>
            <span>{{ $t('正常创建') }}</span>
          </div>
          <div class="bar-item">
            <div class="bar" style="background-color: #FFF69D;"></div>
            <span>{{ $t('继承/聚合') }}</span>
          </div>
        </div> -->
      </div>
    </div>
  </m-window-frame>
</template>

<script lang="ts">
import MWindowFrame from "@/common/ipcWindow/WindowFrame.vue";
import { ref, computed, watch, onBeforeMount, markRaw, onMounted, onBeforeUnmount, nextTick } from "vue";
import AttrTips from "@/common/attrTip/AttrTip.vue";
import { ipcWindowUtil } from "@/mdesign-lib/mdesign-app.umd.js";
import { useRoute } from "vue-router";
import { Params, CloseData } from "./index";
import { modelService } from "@/mdesign-lib/mdesign-app.umd.js";
import { locale } from "@/mdesign-lib/mdesign-app.umd.js";
import { AgGridVue } from "ag-grid-vue3";
import type { GridApi, IRowNode } from "ag-grid-community";
import "ag-grid-community/styles/ag-grid.css";
import "ag-grid-community/styles/ag-theme-alpine.css";
import { archService } from "@/mdesign-lib/mdesign-app.umd.js";
import CellRender from "./CellRender.vue";
import { toMap } from "@/util/common";
import { PropertyRow } from "@/mdesign-lib/mdesign-app.umd.js";
import { ModelData, MenuItem } from "@/mdesign-lib/mdesign-app.umd.js";
import { getHighLightValue, HighLightContent, useTableFreshModelKeys } from "./util";
import { BusEvent, ModuleKey, PropertyKey } from "@/mdesign-lib/mdesign-app.umd.js";
import { useEvents } from "@/mdesign-lib/mdesign-app.umd.js";
import { CreateExchangeWindow } from "../createExchange";
import ContextMenu from "@/common/ContextMenu/index.vue";
import { actionManager } from "@/mdesign-lib/mdesign-app.umd.js";
import { modelHttp } from "@/util/httpClient/ModelHttpClient";
import { API } from "@/mdesign-lib/mdesign-app.umd.js";
import { Project } from "@/mdesign-lib/mdesign-app.umd.js";
import { rmi } from "@/util/IpcWindow/RMI";
import { ipcRenderer } from "electron";
import { IpcMsg, WindowName } from "@/mdesign-lib/mdesign-main.js";
import ModuleModel from "@/mdesign-lib/mdesign-app.umd.js";
import { ModelChangeData } from "@/mdesign-lib/mdesign-app.umd.js";

interface RowValue {
  propertyRow?: PropertyRow;
  content?: HighLightContent[];
  value?: any;
}

interface RowData {
  loaded: number; // -1未载入，0载入中，1载入完成
  id: string;
  selectedKey?: string;
  [key: string]: string | number | RowValue | undefined;
}

export default {
  components: { CellRender, AttrTips, MWindowFrame, AgGridVue },
  setup() {
    const route = useRoute();
    let projectId = "";
    let relationId = "";
    let stereotype = "";
    let exchangeType = "";
    const realizePropertyKeys = [
      "InformationFlow-realization",
      "InformationFlow-realizingConnector",
      "InformationFlow-realizingMessage",
      "InformationFlow-realizingActivityEdge"
    ];
    const canEditPropertyKeys = [
      PropertyKey.NamedElement_name,
      PropertyKey.InformationFlow_conveyed,
      PropertyKey.InformationFlow_informationSource,
      PropertyKey.InformationFlow_informationTarget
    ];

    const { handleAddPropertyModelKeys, clearPropertyModelKeysByRowKey, getRowKeyByPropertyKey } = useTableFreshModelKeys();

    watch(
      () => route.fullPath,
      async () => {
        const routeQuery = route.query as unknown;
        const query = routeQuery as Params;
        stereotype = query.stereotype;
        projectId = query.projectId;
        relationId = query.relationId;
        exchangeType = stereotype.split("::").pop() as string;
      },
      { immediate: true }
    );

    const columnDefs = ref([
      {
        headerName: "#",
        field: "index",
        width: 30,
        valueGetter: indexValueGetter,
        cellStyle: { display: "flex", "align-items": "center" }
      },
      {
        headerName: locale.getTByKey("Realize", "Realize"),
        field: "realize",
        flex: 1,
        sortable: false,
        cellRenderer: "CellRender",
        // cellStyle: { display: 'flex', 'justify-content': 'center' },
        // headerClass: 'align-center',
        cellRendererParams: {
          rendererType: "checkbox"
        }
      },
      {
        headerName: locale.getTByKey(`propertyConfig.${PropertyKey.NamedElement_name}`),
        field: PropertyKey.NamedElement_name,
        flex: 1,
        cellRenderer: "CellRender",
        cellRendererParams: {
          rendererType: "propertyComp"
        }
      },
      {
        headerName: locale.getTByKey(`propertyConfig.${PropertyKey.InformationFlow_conveyed}`),
        field: PropertyKey.InformationFlow_conveyed,
        flex: 1,
        cellRenderer: "CellRender",
        cellRendererParams: {
          rendererType: "propertyComp"
        }
      },
      {
        headerName: locale.getTByKey(`propertyConfig.${PropertyKey.InformationFlow_informationSource}`),
        field: PropertyKey.InformationFlow_informationSource,
        flex: 1,
        cellRenderer: "CellRender",
        cellRendererParams: {
          rendererType: "propertyComp"
        }
      },
      {
        headerName: locale.getTByKey(`propertyConfig.${PropertyKey.InformationFlow_informationTarget}`),
        field: PropertyKey.InformationFlow_informationTarget,
        resizable: false,
        flex: 1,
        cellRenderer: "CellRender",
        cellRendererParams: {
          rendererType: "propertyComp"
        }
      }
    ]);

    const rowData = ref<RowData[]>([]);
    const selectedRow = ref<RowData>(); // 这是点击cell的row
    const selectedRowIds = ref<Set<string>>(new Set()); // 这是select change事件产生的row id

    const defaultColDef = ref({
      resizable: true,
      suppressMovable: true
      // sortable: true, // 数据懒加载，不支持排序
      // comparator: sortComparator,
    });

    const tableRef = ref<GridApi<RowData>>();

    const title = computed(() => {
      const lang = locale.getLocale();
      return locale.t("modelConfig." + exchangeType) + (lang === "en" ? " " : "") + locale.t("Manager");
    });

    const events = {
      [BusEvent.JAVA_MODEL_CHANGE]: async (msg: ModelChangeData) => {
        const updateModelId = msg.update;
        console.log("updateModelId", updateModelId);
        const rowIds = new Set<string>(updateModelId);
        const rowNodes: IRowNode<RowData>[] = [];
        const rowDatas: RowData[] = [];
        updateModelId.forEach(modelId => {
          const ids = getRowKeyByPropertyKey(modelId);
          ids && rowIds.addAll(ids);
        });

        rowIds.forEach(id => {
          const rowNode = tableRef.value?.getRowNode(id);
          rowNode && rowNodes.push(rowNode);
          rowNode?.data && rowDatas.push(rowNode.data);
        });

        if (rowDatas.length) {
          await queryCellPropertyData(rowDatas);
          tableRef.value?.refreshCells({ rowNodes: rowNodes });
          tableRef.value?.resetRowHeights();
        }
      }
    };
    useEvents(events);

    onBeforeMount(async () => {
      await addProject();
      getRowData();
    });

    onMounted(() => {
      // window.addEventListener('resize', sizeColumnsToFit);
    });

    onBeforeUnmount(() => {
      // window.removeEventListener('resize', sizeColumnsToFit);
    });

    // const sizeColumnsToFit = () => {
    //   tableRef.value?.sizeColumnsToFit();

    // };

    const onGridReady = params => {
      tableRef.value = params.api;
      // sizeColumnsToFit();
    };

    const onViewportChanged = data => {
      // console.log('data', data);
      getCellData(data.firstRow, data.lastRow);
    };

    const onCellClicked = data => {
      const oldSelectedRow = selectedRow.value;
      oldSelectedRow && (oldSelectedRow.selectedKey = "");
      selectedRow.value = data.data;
      selectedRow.value!.selectedKey = data.colDef.field;

      const rowNodes: any[] = [];
      [data.data.id, oldSelectedRow?.id].forEach(id => {
        if (id) {
          rowNodes.push(tableRef.value?.getRowNode(id));
        }
      });
      tableRef.value?.refreshCells({ rowNodes: rowNodes, force: true });
      tableRef.value?.resetRowHeights();
    };

    const getRowId = params => params.data.id;

    const getRowData = async () => {
      const list = await archService.queryInformationFlowByRelation(projectId, relationId, stereotype);
      const rowDataList = list.map((item, index) => {
        return {
          index: index + 1,
          loaded: -1,
          id: item.exchangeId
        };
      });
      rowData.value = rowDataList;
    };

    const getCellData = async (firstRow: number, lastRow: number) => {
      const rows = rowData.value.slice(firstRow, lastRow + 1);
      const needLoadRows = rows.filter(row => row.loaded === -1);

      const rowNodes: any[] = [];

      needLoadRows.forEach(row => {
        row.loaded = 0;
        rowNodes.push(tableRef.value?.getRowNode(row.id));
      });
      tableRef.value?.refreshCells({ rowNodes, force: true });

      await queryCellPropertyData(needLoadRows);

      if (rowNodes.length > 0) {
        tableRef.value?.refreshCells({ rowNodes });
        tableRef.value?.resetRowHeights();
      }
    };

    const queryCellPropertyData = async (needLoadRows: RowData[]) => {
      const needLoadRowMap = toMap(needLoadRows);
      const ids = [...needLoadRowMap.keys()];
      if (ids.length) {
        const cellData = await archService.getExchangeManagerCells(projectId, relationId, ids);
        cellData.forEach((data, index) => {
          const currentId = ids[index];
          const currentRowData = needLoadRowMap.get(currentId);
          if (!currentRowData) return;
          currentRowData.loaded = 1;
          data.forEach(propertyRow => {
            const propertyKey = propertyRow.key;
            propertyRow.modelId = currentId;
            if (realizePropertyKeys.includes(propertyKey)) {
              const value = propertyRow.value as ModelData[];
              currentRowData.realize = {
                propertyRow: markRaw(propertyRow),
                value: value.some(model => model.id === relationId)
              };
            } else {
              const content = getHighLightValue(propertyRow);
              currentRowData[propertyKey] = {
                propertyRow: markRaw(propertyRow),
                content
              };
              handleAddPropertyModelKeys(currentId, propertyRow, content);
            }
          });
        });
      }
    };

    // function sortComparator (valueA:RowValue, valueB:RowValue, nodeA, nodeB, isDescending) {
    //   // console.log('sort', valueA, valueB, nodeA, nodeB, isDescending);
    //   return SortNodeUtil.sortByNameOrId(valueA?.content?.[0]?.text || '', valueB?.content?.[0]?.text || '');
    // }

    const getRowHeight = params => {
      const lineHeight = 24;
      const totalBorderHeight = 3;
      const baseRowHeight = lineHeight + totalBorderHeight;
      const data = params.data;
      const selectedKey = data.selectedKey;

      let rowHeight = baseRowHeight;
      canEditPropertyKeys.forEach(key => {
        if (key !== PropertyKey.NamedElement_name) {
          const content = data[key]?.content;
          const length = content?.length || 0;
          const minContentHeight = key === selectedKey ? 40 : 0;
          const height = Math.max(length * lineHeight, minContentHeight) + totalBorderHeight;
          rowHeight = Math.max(rowHeight, height);
        }
      });
      return rowHeight;
    };

    const onSelectionChanged = () => {
      const selectedRows = tableRef.value?.getSelectedRows() || [];
      selectedRowIds.value = new Set(selectedRows.map(item => item.id));
    };

    const createExchange = () => {
      CreateExchangeWindow.popup(
        {
          projectId,
          relationId,
          stereotype
        },
        async result => {
          if (result.success) {
            const itemflowData = result.itemflowData;
            if (itemflowData) {
              const { addModel } = await archService.createExchange(itemflowData);
              CreateExchangeWindow.done();

              const addModelInfos = addModel.length ? await modelService.getModelDatas(projectId, addModel) : [];
              const addExchangeModelIds = addModelInfos.filter(model => model.baseSt === stereotype).map(model => model.id);
              const newRowData = [...rowData.value];
              addExchangeModelIds.forEach(id => {
                newRowData.push({
                  loaded: -1,
                  id
                });
              });

              if (addExchangeModelIds.length) {
                rowData.value = newRowData;
              }
            }
          }
        }
      );
    };

    const deleteExchange = async () => {
      if (selectedRowIds.value.size === 0) return;
      const rowDatas: RowData[] = [];
      const rowIndex: number[] = [];
      selectedRowIds.value.forEach(id => {
        const rowNode = tableRef.value?.getRowNode(id);
        rowNode?.data && rowDatas.push(rowNode.data);
        rowNode?.rowIndex !== undefined && rowNode?.rowIndex !== null && rowIndex.push(rowNode.rowIndex);
      });

      const isRealized = rowDatas.some(row => {
        const rowValue = row["realize"] as RowValue;
        return !!rowValue?.value;
      });

      const msg = isRealized ? "该交换还绑定了其他关系，是否确定删除该交换？" : "是否确定删除该交换？";

      app.$confirm
        .popup({
          title: "删除",
          content: msg,
          showCheckbox: false,
          status: "warn",
          cancelText: "取 消",
          okText: "确 定"
        })
        .then(async () => {
          await modelService.removeModel(projectId, [...selectedRowIds.value]);
          selectedRow.value = undefined;
          const sortedRowIndex = rowIndex.sort((a, b) => b - a);
          console.log("rowIndex", rowIndex);
          const newRowData = [...rowData.value];
          for (let i = 0; i < sortedRowIndex.length; i++) {
            newRowData.splice(sortedRowIndex[i], 1);
          }
          selectedRowIds.value.forEach(rowId => clearPropertyModelKeysByRowKey(rowId));
          rowData.value = newRowData;
          nextTick(() => tableRef.value?.redrawRows());
        });
    };

    const onCellContextMenu = params => {
      // console.log('onCellContextMenu', params);
      const field = params.colDef.field;
      const rowValue = params.data?.[field] as RowValue;
      const content = rowValue?.content;
      const rowNameValue = params.data?.[PropertyKey.NamedElement_name] as RowValue;
      const rowId = params.data?.id;
      const rowName = rowNameValue?.content?.[0]?.text || "";
      const rowIcon = `statics/arch/icon/${exchangeType}.svg`;
      const event = params.event as MouseEvent;

      const childrenMenus: MenuItem[] = [];
      if (content) {
        const modelValues = content.filter(item => item.isModel);
        modelValues.forEach(value => {
          childrenMenus.push({
            instanceId: value!.modelId,
            label: value.text,
            icon: value.icon,
            value: "",
            keyName: "instanceId"
          });
        });
      }
      if (childrenMenus.length) {
        childrenMenus.unshift({
          instanceId: rowId,
          label: rowName,
          icon: rowIcon,
          value: "",
          keyName: "instanceId"
        });
      }

      const menuItems: MenuItem[] = [
        {
          label: "属性设置",
          value: "showAttribute",
          icon: "statics/icons/app/iconproperty2.svg",
          instanceId: rowId,
          children: childrenMenus.map(item => ({ ...item, value: "showAttribute" }))
        },
        {
          label: "树上高亮",
          value: "selectOnTree",
          icon: "statics/icons/table/showModelPosition.svg",
          instanceId: rowId,
          children: childrenMenus.map(item => ({ ...item, value: "selectOnTree" }))
        }
      ];

      ContextMenu.popup({
        x: event.clientX,
        y: event.clientY,
        menuItems: menuItems
      })
        .then(async res => {
          const { value, instanceId } = res;
          if (value === "selectOnTree") {
            await rmi.invokeAction(value, [
              [instanceId],
              { scroll: true, changeTab: true, isModelLibrary: false, modelLibraryProjectId: "", skipConfirm: true }
            ]);
            ipcRenderer.send(IpcMsg.WindowFocus, WindowName.MainWindow); //  向主窗口发送消息，将主窗口激活
          } else {
            const action = actionManager.getAction(value);
            const node = await modelService.loadGraphNode(projectId, instanceId);
            if (!action?.onTreeMenuClick || !node) return;
            action.onTreeMenuClick(node, null);
          }
        })
        .catch(err => console.log(err));
    };

    const addProject = async () => {
      const projectConfig = await modelHttp.get(API.MODEL_SERVICE_PROJECT_INFO, { projectId }).then(res => res.data);

      const project = new Project(projectConfig);
      project.init();

      app.projectManager.addProject(project);
      await app.projectManager.switchProject(project.id);
      const modelModule = app.moduleManager.getModule(ModuleKey.MODEL) as ModuleModel;
      modelModule.socketService.sendJSON({ type: "subscribeProject", projectId: projectId });
    };

    function indexValueGetter(params) {
      return params.node.rowIndex + 1;
    }

    function handleclose(data: CloseData) {
      ipcWindowUtil.closeWindow(data);
    }

    function handleCancel() {
      handleclose({ windowName: "CreateExchangeManagerWindow", success: false });
    }

    return {
      columnDefs,
      defaultColDef,
      rowData,
      title,
      relationId,
      handleCancel,
      selectedRowIds,
      exchangeType,
      onGridReady,
      onViewportChanged,
      getRowId,
      onCellClicked,
      getRowHeight,
      createExchange,
      deleteExchange,
      onSelectionChanged,
      onCellContextMenu
    };
  }
};
</script>
<style lang="scss">
.v-create-exchange-editor-manager {
  ._main {
    height: 100%;
    ._main-content {
      flex: 1;
      display: flex;
      flex-direction: column;
      overflow: hidden;
      padding: 12px 16px;
      .button-area {
        margin-bottom: 12px;
        display: flex;
        .button-item {
          height: 20px;
          margin-right: 8px;
          display: flex;
          align-items: center;
          padding: 0 4px;
          cursor: pointer;
          color: #5f6c88;
          img {
            width: 16px;
            height: 16px;
            margin-right: 4px;
          }
          &:hover {
            background-color: var(--background-color-active);
            color: #fff;
          }
          &.disabled {
            cursor: not-allowed;
            background-color: #fff;
            color: #a8abb2;
            img {
              opacity: 0.25;
            }
          }
        }
      }
      .bar-area {
        display: flex;
        margin-top: 12px;
        .bar-item {
          margin-right: 24px;
          display: flex;
          align-items: center;
          color: rgba(0, 0, 0, 0.85);
          .bar {
            width: 50px;
            height: 10px;
            border: 1px solid #e0e0e0;
            margin-right: 6px;
          }
        }
      }
      .table-area {
        flex: 1;
      }
    }
  }

  .ag-theme-mdesigntheme {
    --ag-odd-row-background-color: #fff;
    --ag-border-color: #e0e0e0;
    --ag-row-border-color: #e0e0e0;
    --ag-cell-horizontal-border: 1px solid #e0e0e0;
    --ag-header-column-resize-handle-height: 100%;
    --ag-header-column-resize-handle-width: 1px;
    --ag-header-column-resize-handle-color: #e0e0e0;
    --ag-header-background-color: #ecf0ff;
    --ag-cell-horizontal-padding: 9px;
    .ag-row {
      .ag-cell:last-of-type {
        --ag-cell-horizontal-border: 1px solid transparent;
      }
    }
  }
}
</style>
